require_relative 'sudoku2'

def printNodeAndConstraints(n)
     puts n.to_s
     print "\n---\n"
     n.constraints.each {|c| print c.description, "\n"} unless n.constraints.nil?
     print "\n"
end

def printConstraintAndNodes(c)
     print c.description, "\n" 
     c.nodes.each do |n|
          print " -Node: "
          puts n.to_s
          print "\n---\n"
     end
end

def printNode(n)
    puts n.to_s
end
#
#
#Tests are below
#
#

def printArrayTest ()
     a = [[1]]
     printArray(a)
     print "\n"

     a = [[1,1],[2,2]]
     printArray(a)
     print "\n"

     a = Array.new(1) { Array.new(1) {0} }
     printArray(a)
     puts "\n"

     a = Array.new(2) { Array.new(2) {0} }
     printArray(a)
     puts "\n"

     a = Array.new(3) { Array.new(3) {0} }
     printArray(a)
     puts "\n"

     a = Array.new(9) { Array.new(9) {15} }
     printArray(a)
     puts "\n"
     
     a = [[1,2,3],[2,3,1],[3,1,2]]
     printArray(a)
     puts "\n"
end

def solvePuzzleTest()
#     a = Array.new(1) { Array.new(1) {0} }
#     m = Array.new(1) { Array.new(1) {1}}
#     a = solvePuzzle(a,m)
#     printArray(a)
#     print "\n"
#
#     a = Array.new(2) { Array.new(2) {0} }
#     m = [[1,1],[2,2]]
#     a = solvePuzzle(a,m)
#     printArray(a)
#     print "\n"
#     
#     m = [[1,2,3],[2,3,1],[3,1,2]]
#     a = Array.new(m.length) {Array.new(m.length) {0}}
#     a = solvePuzzle(a,m)
#     printArray(a)
#     print "\n"
#     
#     m = getSudokuMatrix
#     a = Array.new(m.length) {Array.new(m.length) {0}}
#     a = solvePuzzle(a,m)
#     printArray(a)
#     print "\n"
#     
#     m = [[1]]
#     a = [[1]]
#     a = solvePuzzle(a,m)
#     printArray(a)
#     print "\n"
#     
#     a = [[1,2],[2,0]]
#     m = [[1,1],[2,2]]
#     a = solvePuzzle(a,m)
#     printArray(a)
#     print "\n"
#     
#     a = [[1,0],[2,0]]
#     m = [[1,1],[2,2]]
#     a = solvePuzzle(a,m)
#     printArray(a)
#     print "\n"
#     
#     a = [[0,0],[2,0]]
#     m = [[1,1],[2,2]]
#     a = solvePuzzle(a,m)
#     printArray(a)
#     print "\n"
#     
#     
#     m = [[1,2,3],[2,3,1],[3,1,2]]
#     a = [[1,3,0],[0,1,0],[0,0,0]]
#     a = solvePuzzle(a,m)
#     printArray(a)
#     print "\n"
#     
#     m = [[1,1,3,3],[1,1,3,3],[2,2,4,4],[2,2,4,4]]
#     a = [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]
#     a = solvePuzzle(a,m)
#     printArray(a)
#     print "\n"
#
#     m = [[1,1,3,3],[1,1,3,3],[2,2,4,4],[2,2,4,4]]
#     a = [[0,0,0,1],[0,1,0,0],[0,0,0,0],[1,0,0,4]]
#     a = solvePuzzle(a,m)
#     printArray(a)
#     print "\n"
#     
#     m = STD_BOX_MATRIX
#     a = [[3,4,0,0,0,0,0,0,0],[0,0,0,8,0,0,0,0,0],[7,0,0,0,0,0,8,0,3],[9,0,3,0,4,0,0,0,0],[0,0,6,0,0,0,0,7,0],[0,0,0,0,0,9,3,2,0],[0,0,1,2,0,0,0,0,6],[2,0,0,1,0,5,0,0,0],[0,0,5,7,0,0,9,0,0]]
#     a = solvePuzzle(a,m)
#     printArray(a)
#     print "\n"
#
     m = STD_BOX_MATRIX
     a =[[3,0,0,0,7,0,0,8,0],[0,0,0,0,9,0,0,0,7],[8,0,0,0,0,0,0,5,2],[0,1,0,0,3,7,0,0,0],[0,0,2,0,0,0,1,0,0],[0,4,6,0,1,5,8,0,0],[0,0,0,0,0,0,0,4,0],[0,0,0,4,0,0,0,0,3],[1,0,0,3,6,0,0,0,0]]
     a = solvePuzzle(a,m)
     printArray(a)
     print "\n"
     
end

def preloadPuzzleTest()
     a = [[2]]
     node = Node.new(1,1,2)
     nodes = [node]
     constraints = []
     solution = preloadPuzzle(a,nodes, constraints)
     solution.each do |n|
          puts n.to_s
          print "\n"
     end
     print "\n"
     
     a = [[2, 1],[1,2]]
     node = Node.new(1,1,2)
     n2 = Node.new(1,2,1)
     nodes = [node, n2]
     constraints = []
     solution = preloadPuzzle(a,nodes, constraints)
     solution.each do |n|
          puts n.to_s
          print "\n"
     end
end

def findNodesTest()
     n = Node.new(1,1,1)
     nodeList = [n]
     nodes = findNodes(nodeList, 0, 1)
     nodes.each do |node| 
          puts node.to_s
          print "\n" 
     end
     print "none found\n" unless nodes.length > 0
     print "\n"

     n = Node.new(1,1,1)
     nodeList = [n]
     nodes = findNodes(nodeList, 1, 1, 2)
     nodes.each do |node| 
          puts node.to_s
          print "\n" 
     end
     print "none found\n" unless nodes.length > 0
     print "\n"

     n = Node.new(1,1,1)
     n = Node.new(1,1,2)
     nodeList = [n]
     nodes = findNodes(nodeList, 1, 1, 2)
     nodes.each do |node| 
          puts node.to_s
          print "\n" 
     end
     print "none found\n" unless nodes.length > 0
     print "\n"

     n = Node.new(1,1,1)
     m = Node.new(1,1,2)
     nodeList = [n,m]
     nodes = findNodes(nodeList, 1, 1)
     nodes.each do |node| 
          puts node.to_s
          print "\n" 
     end
     print "none found\n" unless nodes.length > 0
     print "\n"
     
     n = Node.new(1,1,1)
     m = Node.new(1,1,2)
     nodeList = [n,m]
     nodes = findNodes(nodeList, 0, 1)
     nodes.each do |node| 
          puts node.to_s
          print "\n" 
     end
     print "none found\n" unless nodes.length > 0
     print "\n"
     
     nodeList = getNodes(2)
     nodes = findNodes(nodeList, 2, 1)
     nodes.each do |node| 
          puts node.to_s
          print "\n" 
     end
     print "none found\n" unless nodes.length > 0
     print "\n"
     
end

def printNodeTest()
     n = Node.new(1,1,1)
     puts node.to_s
     
     n = Node.new(1,2,4)
     puts node.to_s
     
     n = Node.new(7,9,14)
     puts node.to_s
     
end

def removeNodeTest()
    #Test 1
    
    print "\nTEST 1\n----------\n"
    node = Node.new(1,1,1)
    constraints = []
    removeNode(node, constraints)
    print "\nNode and its Constraints\n------\n"
    printNodeAndConstraints(node)
    print "\n"
    print "\nConstraints and Their Nodes\n------\n"
    node.constraints.each { |c| printConstraintAndNodes(c)}
    print "\n"
    print "\nOutgoing Constraints\n=========\n"
    constraints.each { |c| print c.description, "\n" }
    print "\n"
    print "\nNodes that also Satisfy Constraints and their constraints \n--------\n" 
    node.constraints.each do |c|
          c.nodes.each do |n|
               printNodeAndConstraints(n)
          end
    end
    print "\nCousin constraints and the nodes that satisfy them\n--------------\n"
    node.constraints.each do |c|
          c.nodes.each do |n|
               n.each do |x|
                    printConstraintAndNodes(x)
               end
          end
     end
     
     #Test 2
    
    print "\nTEST 2\n----------\n"
    node = Node.new(1,1,1)
    c1 = Constraint.new('test')
    constraints = [c1]
    removeNode(node, constraints)
    print "\nNode and its Constraints\n------\n"
    printNodeAndConstraints(node)
    print "\n"
    print "\nConstraints and Their Nodes\n------\n"
    node.constraints.each { |c| printConstraintAndNodes(c)}
    print "\n"
    print "\nOutgoing Constraints\n=========\n"
    constraints.each { |c| print c.description, "\n" }
    print "\n"
    print "\nNodes that also Satisfy Constraints and their constraints \n--------\n" 
    node.constraints.each do |c|
          c.nodes.each do |n|
               printNodeAndConstraints(n)
          end
    end
    print "\nCousin constraints and the nodes that satisfy them\n--------------\n"
    node.constraints.each do |c|
          c.nodes.each do |n|
               n.each do |x|
                    printConstraintAndNodes(x)
               end
          end
     end
    
     #Test 3
    
    print "\nTEST 3\n----------\n"
    node = Node.new(1,1,1)
    c1 = Constraint.new('test')
    node.constraints = [c1]
    constraints = [c1]
    removeNode(node, constraints)
    print "\nNode and its Constraints\n------\n"
    printNodeAndConstraints(node)
    print "\n"
    print "\nNode's Constraints and Their Nodes\n------\n"
    node.constraints.each { |c| printConstraintAndNodes(c)}
    print "\n"
    print "\nOutgoing Constraints\n=========\n"
    constraints.each { |c| print c.description, "\n" }
    print "\n"
    print "\nNodes that also Satisfy Constraints and their constraints \n--------\n" 
    node.constraints.each do |c|
          c.nodes.each do |n|
               printNodeAndConstraints(n)
          end
    end
    print "\nCousin constraints and the nodes that satisfy them\n--------------\n"
    node.constraints.each do |c|
          c.nodes.each do |n|
               n.each do |x|
                    printConstraintAndNodes(x)
               end
          end
     end    
     
     #Test 4
    
    print "\nTEST 4\n----------\n"
    node = Node.new(1,1,1)
    c1 = Constraint.new('test')
    c1.nodes = [node]
    node.constraints = [c1]
    constraints = [c1]
    removeNode(node, constraints)
    print "\nNode and its Constraints\n------\n"
    printNodeAndConstraints(node)
    print "\n"
    print "\nNode's Constraints and Their Nodes\n------\n"
    node.constraints.each { |c| printConstraintAndNodes(c)} unless node.constraints.nil?
    print "\n"
    print "\nOutgoing Constraints\n=========\n"
    constraints.each { |c| print c.description, "\n" } unless constraints.nil?
    print "\n"
    print "\nNodes that also Satisfy Constraints and their constraints \n--------\n" 
    node.constraints.each do |c|
          c.nodes.each do |n|
               printNodeAndConstraints(n)
          end unless c.nodes.nil?
    end unless node.constraints.nil?
    print "\nCousin constraints and the nodes that satisfy them\n--------------\n"
    node.constraints.each do |c|
          c.nodes.each do |n|
               n.constraints.each do |x|
                    printConstraintAndNodes(x)
               end unless n.nil?
          end unless c.nodes.nil?
     end  unless node.constraints.nil?
     
      #Test 5
    
    print "\nTEST 5\n----------\n"
    node = Node.new(1,1,1)
    c1 = Constraint.new('test')
    c2 = Constraint.new('test2')
    c1.nodes = [node]
    c2.nodes = [node]
    node.constraints = [c1,c2]
    constraints = [c1,c2]
    removeNode(node, constraints)
    print "\nNode and its Constraints\n------\n"
    printNodeAndConstraints(node)
    print "\n"
    print "\nNode's Constraints and Their Nodes\n------\n"
    node.constraints.each { |c| printConstraintAndNodes(c)} unless node.constraints.nil?
    print "\n"
    print "\nOutgoing Constraints\n=========\n"
    constraints.each { |c| print c.description, "\n" } unless constraints.nil?
    print "\n"
    seen = []
    print "\nNodes that also Satisfy Constraints and their constraints \n--------\n" 
    node.constraints.each do |c|
          c.nodes.each do |n|
               printNodeAndConstraints(n) unless seen.include?(n)
               seen.push(n)
          end unless c.nodes.nil?
    end unless node.constraints.nil?
    print "\nCousin constraints and the nodes that satisfy them\n--------------\n"
    node.constraints.each do |c|
          c.nodes.each do |n|
               n.constraints.each do |x|
                    printConstraintAndNodes(x) unless seen.include?(x)
                    seen.push(x)
               end unless n.nil?
          end unless c.nodes.nil?
     end  unless node.constraints.nil?
     
end

def printConstraintTest()
    c = Constraint.new('This is a constraint')
    puts c.to_s
    print "\n\n"
    
    c = Constraint.new('This is a constraint')
    c.value = 1
    c.row = 1
    puts c.to_s
    print "\n"
end

def getNodesTest()
     nodes = getNodes(1)
     nodes.each {|node| puts node.to_s}
     print "\n"
     
     nodes = getNodes(2)
     nodes.each {|node| puts node.to_s}
     print "\n"
     
     nodes = getNodes(3)
     nodes.each {|node| puts node.to_s}
     print "\n"
     
end

def getConstraintsTest()
     m = [[1]]
     constraints = getConstraints(m)
     constraints.each {|c| printConstraint(c)}
     print "\n"
     
     m = [[1,2], [1,2]]
     constraints = getConstraints(m)
     constraints.each {|c| puts c.to_s}
     print "\n"
     
end

def getSudokuMatrixTest()
     m = STD_BOX_MATRIX
     printArray(m)
end

def assignNodesToConstraintsTest()
     nodes = getNodes(1)
     m = [[1]]
     constraints = getConstraints(1)
     assignNodesToConstraints(nodes, constraints, makeGroupList(m))
     nodes.each do |n| 
          puts n.to_s
          print "\nlength of constraints list - ", n.constraints.length, "\n"
          n.constraints.each { |c| print c.description, "\n"}
          print "\n"
     end
     print "\n"
     constraints.each do |c| 
          print c.description, "\n"
          print "length of nodes list - ", c.nodes.length, "\n"
          c.nodes.each do |n| 
            puts n.to_s
               print "\n"
          end
          print "\n"
     end
     print "\n"
     print "\n"
     
     m = [[1,1],[2,2]]
     nodes = getNodes(m.length)
     constraints = getConstraints(m.length)
     assignNodesToConstraints(nodes, constraints, makeGroupList(m))
     nodes.each do |n| 
        puts n.to_s
          print "\nlength of constraints list - ", n.constraints.length, "\n"
          n.constraints.each { |c| print c.description, "\n"}
          print "\n"
     end
     print "\n"
     constraints.each do |c| 
          print c.description, "\n"
          print "length of nodes list - ", c.nodes.length, "\n"
          c.nodes.each do |n| 
            puts n.to_s
               print "\n"
          end
          print "\n"
     end
     print "\n"
     print "\n"
     
     m = [[1,2,3],[2,3,1],[3,1,2]]
     nodes = getNodes(m.length)
     constraints = getConstraints(m.length)
     assignNodesToConstraints(nodes, constraints, makeGroupList(m))
     nodes.each do |n| 
          printNode(n)
          print "\nlength of constraints list - ", n.constraints.length, "\n"
          n.constraints.each { |c| print c.description, "\n"}
          print "\n"
     end
     print "\n"
     constraints.each do |c| 
          print c.description, "\n"
          print "length of nodes list - ", c.nodes.length, "\n"
          c.nodes.each do |n| 
               printNode(n)
               print "\n"
          end
          print "\n"
     end
     print "\n"
     print "\n"
     
     m = STD_BOX_MATRIX
     nodes = getNodes(m.length)
     constraints = getConstraints(m.length)
     assignNodesToConstraints(nodes, constraints, makeGroupList(m))
     nodes.each do |n| 
          printNode(n)
          print "\nlength of constraints list - ", n.constraints.length, "\n"
          n.constraints.each { |c| print c.description, "\n"}
          print "\n"
     end
     print "\n"
     constraints.each do |c| 
          print c.description, "\n"
          print "length of nodes list - ", c.nodes.length, "\n"
          c.nodes.each do |n| 
               printNode(n)
               print "\n"
          end
          print "\n"
     end
     print "\n"
     print "\n"
end

def makeGroupListTest()
     m = [[1]]
     g = makeGroupList(m)
     printArray(g) if g
     print "\n"
     
     m = [[1,1],[2,2]]
     g = makeGroupList(m)
     printArray(g) if g
     print "\n"
     
     m = [[1,2,3],[2,3,1],[3,2,1]]
     g = makeGroupList(m)
     printArray(g) if g
     print "\n"
     
end

def findNextConstraintTest()
     m = [[1]]
     constraints = getConstraints(m.length)
     nodes = getNodes(m.length)
     assignNodesToConstraints(nodes, constraints, makeGroupList(m))
     nextConstraint = findNextConstraint(constraints)
     print nextConstraint.description, "\n"
     
     m = [[1,2], [2,1]]
     constraints = getConstraints(m.length)
     nodes = getNodes(m.length)
     assignNodesToConstraints(nodes, constraints, makeGroupList(m))
     nextConstraint = findNextConstraint(constraints)
     print "nothing found" unless nextConstraint
     currentNode = nextConstraint.nodes[0] if nextConstraint
     
     currentNode.constraints.each do |con|
          constraints.delete(con)
          print "fulfiled constraint ", con.description, " with node "
          printNode(node)
          print "...\n"
          print "There were a total of ", con.nodes.length, " nodes that could fulfill it"
          # for current constraint, remove other nodes that would fulfil it
          # from the nodes list of each constraint in their constraints lists.               
          con.nodes.each do |node|
               print "With node " 
               printNode(currentNode)
               print "\n"
               node.constraints.each do |c| 
                    print "So removing "
                    printNode(node)
                    print " from the list of constraint ", c.description, "\n"
                    c.nodes.delete(node) 
               end
          end
     end
     
     nextConstraint = findNextConstraint(constraints)
     print "nothing found", "\n" unless nextConstraint
     print nextConstraint.description, "\n" if nextConstraint
     print "\n\n"
     
     m = [[1,1], [2,2]]
     constraints = getConstraints(m.length)
     nodes = getNodes(m.length)
     assignNodesToConstraints(nodes, constraints, makeGroupList(m))
     nextConstraint = findNextConstraint(constraints)
     print "nothing found", "\n" unless nextConstraint
     currentNode = nextConstraint.nodes[0] if nextConstraint
     
     currentNode.constraints.each do |con|
          constraints.delete(con)
          print 'fulfiled constraint "', con.description, '" With node '
          printNode(currentNode)
          print "\n"
          # for current constraint, remove other nodes that would fulfil it
          # from the nodes list of each constraint in their constraints lists.               
          print "There are ", con.nodes.length, " nodes that could also fill this\n"
          con.nodes.each do |node|
               print "One is "
               printNode(node)
               print ". \n"
               node.constraints.each do |c| 
                    print "So removing "
                    printNode(node)
                    print " from the list of constraint ", c.description, "\n"
                    c.nodes.delete(node) 
               end
          end
     end
     
     nextConstraint = findNextConstraint(constraints)
     print "nothing found" unless nextConstraint
     print nextConstraint.description, "\n" if nextConstraint
     currentNode = nextConstraint.nodes[0] if nextConstraint
     
     currentNode.constraints.each do |con|
          constraints.delete(con)
          print 'fulfiled constraint "', con.description, '" With node '
          printNode(currentNode)
          print "\n"
          # for current constraint, remove other nodes that would fulfil it
          # from the nodes list of each constraint in their constraints lists.               
          print "There are ", con.nodes.length, " nodes that could also fill this\n"
          con.nodes.each do |node|
               print "One is "
               printNode(node)
               print ". \n"
               node.constraints.each do |c| 
                    print "So removing "
                    printNode(node)
                    print " from the list of constraint ", c.description, "\n"
                    c.nodes.delete(node) 
               end
          end
     end
     nextConstraint = findNextConstraint(constraints)
     print "nothing found" unless nextConstraint
     print nextConstraint.description, "\n" if nextConstraint
end

def addToStackTest()
     stack = []
     nodes = []
     addToStack(nodes, stack, 0)
     print stack, "\n"
     
     stack = [1]
     nodes = [2]
     addToStack(nodes, stack, 3)
     print stack, "\n"
     
     stack = [1]
     nodes = [2,3]
     addToStack(nodes, stack, 7)
     print stack, "\n"
     
     stack = [1,2]
     nodes = [2,3]
     addToStack(nodes, stack, 9)
     print stack, "\n"

     stack = [1,2,3,4,5,6,7,8,9,10]
     nodes = [2,4,5,6,7,8,8,9,9,0,29]
     addToStack(nodes, stack, 12)
     print stack
     print "\n"

end

def turnSolutionIntoArrayTest()
     solution = []
     array = turnSolutionIntoArray(solution, 1)
     printArray(array)
     
     n = Node.new(1,1,1)
     solution = [n]
     array = turnSolutionIntoArray(solution, 1)
     printArray(array)
     
     n = Node.new(1,1,1)
     m = Node.new(2,1,1)
     solution = [n, m]
     array = turnSolutionIntoArray(solution, 2)
     printArray(array)
end

def backtrackTest()
     #Test 1
     
     puts "\nTest 1\n-------\n"
     i = 0
     n1 = Node.new(1,2,3)
     solution = [n1]
     constraints = []
     print "\nIncoming Solution Constraints By Node\n=======\n"
     solution.each do |n|
          printNode(n)
          print "\n---\n"
          n.constraints.each {|c| print c.description, "\n"} unless n.constraints.nil?
     end
     print "\n"
     
     print "Incoming Constraints\n=============\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"
     
     backtrack(solution, i, constraints)
     
     print "\nOutgoing Solution Constraints By Node\n=======\n"
     solution.each do |n|
          printNode(n)
          print "\n---\n"
          n.constraints.each {|c| print c.description, "\n"} unless n.constraints.nil?
     end
     print "\n"
     
     print "Outgoing Constraints\n=============\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"
     
     #Test 2
     
     puts "\nTest 2\n-------\n"
     i = 0
     n1 = Node.new(1,2,3)
     n2 = Node.new(2,3,4)
     solution = [n1, n2]
     constraints = []
     print "\nIncoming Solution Constraints By Node\n=======\n"
     solution.each do |n|
          printNode(n)
          print "\n---\n"
          n.constraints.each {|c| print c.description, "\n"} unless n.constraints.nil?
     end
     print "\n"
     
     print "Incoming Constraints\n=============\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"
     
     backtrack(solution, i, constraints)
     
     print "\nOutgoing Solution Constraints By Node\n=======\n"
     solution.each do |n|
          printNode(n)
          print "\n---\n"
          n.constraints.each {|c| print c.description, "\n"} unless n.constraints.nil?
     end
     print "\n"
     
     print "Outgoing Constraints\n=============\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"

     #Test 3
     
     puts "\nTest 3\n-------\n"
     i = 1
     n1 = Node.new(1,2,3)
     n2 = Node.new(2,3,4)
     solution = [n1, n2]
     constraints = []
     print "\nIncoming Solution Constraints By Node\n=======\n"
     solution.each do |n|
          printNode(n)
          print "\n---\n"
          n.constraints.each {|c| print c.description, "\n"} unless n.constraints.nil?
     end
     print "\n"
     
     print "Incoming Constraints\n=============\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"
     
     backtrack(solution, i, constraints)
     
     print "\nOutgoing Solution Constraints By Node\n=======\n"
     solution.each do |n|
          printNode(n)
          print "\n---\n"
          n.constraints.each {|c| print c.description, "\n"} unless n.constraints.nil?
     end
     print "\n"
     
     print "Outgoing Constraints\n=============\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"
          
     #Test 4
     
     puts "\nTest 4\n-------\n"
     i = 1
     n1 = Node.new(1,2,3)
     n2 = Node.new(2,3,4)
     solution = [n1, n2]
     constraints = []
     print "\nIncoming Solution Constraints By Node\n=======\n"
     solution.each do |n|
          printNode(n)
          print "\n---\n"
          n.constraints.each {|c| print c.description, "\n"} unless n.constraints.nil?
     end
     print "\n"
     
     print "Incoming Constraints\n=============\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"
     
     backtrack(solution, i, constraints)
     
     print "\nOutgoing Solution Constraints By Node\n=======\n"
     solution.each do |n|
          printNode(n)
          print "\n---\n"
          n.constraints.each {|c| print c.description, "\n"} unless n.constraints.nil?
     end
     print "\n"
     
     print "Outgoing Constraints\n=============\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"
          
     #Test 5
     
     puts "\nTest 5\n-------\n"
     i = 1
     n1 = Node.new(1,2,3)
     n2 = Node.new(2,3,4)
     c1 = Constraint.new("test constraint 1")
     solution = [n1, n2]
     constraints = [c1]
     print "\nIncoming Solution Constraints By Node\n=======\n"
     solution.each do |n|
          printNode(n)
          print "\n---\n"
          n.constraints.each {|c| print c.description, "\n"} unless n.constraints.nil?
     end
     print "\n"
     
     print "Incoming Constraints\n=============\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"
     
     backtrack(solution, i, constraints)
     
     print "\nOutgoing Solution Constraints By Node\n=======\n"
     solution.each do |n|
          printNode(n)
          print "\n---\n"
          n.constraints.each {|c| print c.description, "\n"} unless n.constraints.nil?
     end
     print "\n"
     
     print "Outgoing Constraints\n=============\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"
          
     #Test 6
     
     puts "\nTest 6\n-------\n"
     i = 1
     n1 = Node.new(1,2,3)
     n2 = Node.new(2,3,4)
     c1 = Constraint.new("test constraint 1")
     solution = [n1, n2]
     n1.constraints = [c1]
     constraints = []
     print "\nIncoming Solution Constraints By Node\n=======\n"
     solution.each do |n|
          printNode(n)
          print "\n---\n"
          n.constraints.each {|c| print c.description, "\n"} unless n.constraints.nil?
     end
     print "\n"
     
     print "Incoming Constraints\n=============\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"
     
     backtrack(solution, i, constraints)
     
     print "\nOutgoing Solution Constraints By Node\n=======\n"
     solution.each do |n|
          printNode(n)
          print "\n---\n"
          n.constraints.each {|c| print c.description, "\n"} unless n.constraints.nil?
     end
     print "\n"
     
     print "Outgoing Constraints\n=============\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"
    
     #Test 7
     
     puts "\nTest 7\n-------\n"
     i = 1
     n1 = Node.new(1,2,3)
     n2 = Node.new(2,3,4)
     c1 = Constraint.new("test constraint 1")
     solution = [n1, n2]
     n2.constraints = [c1]
     constraints = []
     print "\nIncoming Solution Constraints By Node\n=======\n"
     solution.each do |n|
          printNode(n)
          print "\n---\n"
          n.constraints.each {|c| print c.description, "\n"} unless n.constraints.nil?
     end
     print "\n"
     
     print "Incoming Constraints\n=============\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"
     
     backtrack(solution, i, constraints)
     
     print "\nOutgoing Solution Constraints By Node\n=======\n"
     solution.each do |n|
          printNode(n)
          print "\n---\n"
          n.constraints.each {|c| print c.description, "\n"} unless n.constraints.nil?
     end
     print "\n"
     
     print "Outgoing Constraints\n=============\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"
     
     #Test 8
     
     puts "\nTest 8\n-------\n"
     i = 1
     n1 = Node.new(1,2,3)
     n2 = Node.new(2,3,4)
     c1 = Constraint.new("test constraint 1")
     c2 = Constraint.new("test constraint 2")
     solution = [n1, n2]
     n2.constraints = [c1, c2]
     constraints = []
     print "\nIncoming Solution Constraints By Node\n=======\n"
     solution.each do |n|
          printNode(n)
          print "\n---\n"
          n.constraints.each {|c| print c.description, "\n"} unless n.constraints.nil?
     end
     print "\n"
     
     print "Incoming Constraints\n=============\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"
     
     backtrack(solution, i, constraints)
     
     print "\nOutgoing Solution Constraints By Node\n=======\n"
     solution.each do |n|
          printNode(n)
          print "\n---\n"
          n.constraints.each {|c| print c.description, "\n"} unless n.constraints.nil?
     end
     print "\n"
     
     print "Outgoing Constraints\n=============\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"
     
     #Test 9
     
     puts "\nTest 9\n-------\n"
     i = 1
     n1 = Node.new(1,2,3)
     n2 = Node.new(2,3,4)
     c1 = Constraint.new("test constraint 1")
     c2 = Constraint.new("test constraint 2")
     solution = [n1, n2]
     n2.constraints = [c1]
     n1.constraints = [c2]
     constraints = []
     print "\nIncoming Solution Constraints By Node\n=======\n"
     solution.each do |n|
          printNode(n)
          print "\n---\n"
          n.constraints.each {|c| print c.description, "\n"} unless n.constraints.nil?
     end
     print "\n"
     
     print "Incoming Constraints\n=============\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"
     
     backtrack(solution, i, constraints)
     
     print "\nOutgoing Solution Constraints By Node\n=======\n"
     solution.each do |n|
          printNode(n)
          print "\n---\n"
          n.constraints.each {|c| print c.description, "\n"} unless n.constraints.nil?
     end
     print "\n"
     
     print "Outgoing Constraints\n=============\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"
     
     #Test 10
     
     puts "\nTest 10\n-------\n"
     i = 0
     n1 = Node.new(1,2,3)
     n2 = Node.new(2,3,4)
     c1 = Constraint.new("test constraint 1")
     c2 = Constraint.new("test constraint 2")
     solution = [n1]
     n1.constraints = [c1]
     c1.nodes = [n2]
     n2.constraints = [c2]
     constraints = []
     print "\nIncoming Solution Constraints By Node\n=======\n"
     solution.each do |n|
          printNode(n)
          print "\n---\n"
          n.constraints.each {|c| print c.description, "\n"} unless n.constraints.nil?
     end
     print "\n"
     
     print "Incoming Constraints\n=============\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"
     
     oldConstraints = Array.new(constraints)
     oldNodes = Array.new(solution)
     backtrack(solution, i, constraints)
     newConstraints = constraints.select {|c| oldConstraints.include?(c) == false}
     removedNodes = oldNodes.select {|n| solution.include?(n) == false}
     
     print "\nOutgoing Solution Constraints By Node\n=======\n"
     solution.each do |n|
          printNode(n)
          print "\n---\n"
          n.constraints.each {|c| print c.description, "\n"} unless n.constraints.nil?
     end
     print "\n"
     
     print "Outgoing Constraints\n=============\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"
     
     print "\nNew Outgoing Constraints and their Node Lists\n===========\n"
     newConstraints.each do |c| 
          print c.description, "\n" 
          c.nodes do |n|
               print " -Node: "
               printNode(n)
               print "\n---\n"
          end
     end unless newConstraints.nil?
     print "\n"
     
     print "Removed Nodes and their constraint lists\n===============\n"
     removedNodes.each do |n|
          printNode(n)
          print "\n---\n"
          n.constraints.each {|c| print c.description, "\n"} unless n.constraints.nil?
     end
     print "\n"
     
end

def fixConstraintsTest()
     #Test 1
     print "TEST 1\n-----------\n"
     node = Node.new(1,1,1)
     constraints = []
     print "\n Node = "
     printNode(node)
     print "\n========\n"
     node.constraints.each { |c| print c.description, "\n" } unless node.constraints.nil?
     print "\n"
     print "Incoming Constraints\n========\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n\n"
     fixConstraints(node,constraints)
     
     print "\n Node = "
     printNode(node)
     print "\n========\n"
     node.constraints.each { |c| print c.description, "\n" } unless node.constraints.nil?
     print "\n"
     print "Outgoing Constraints\n========\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"
     
     #Test 2
     print "TEST 2\n-----------\n"
     node = Node.new(1,1,1)
     c1 = Constraint.new("test1")
     constraints = [c1]
     print "\n Node = "
     printNode(node)
     print "\n========\n"
     node.constraints.each { |c| print c.description, "\n" } unless node.constraints.nil?
     print "\n"
     print "Incoming Constraints\n========\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n\n"
     fixConstraints(node,constraints)
     
     print "\n Node = "
     printNode(node)
     print "\n========\n"
     node.constraints.each { |c| print c.description, "\n" } unless node.constraints.nil?
     print "\n"
     print "Outgoing Constraints\n========\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"
     
     #Test 3
     print "TEST 3\n-----------\n"
     node = Node.new(1,1,1)
     c1 = Constraint.new('TestConstraint')
     constraints = []
     node.constraints = [c1]
     print "\nNode = "
     printNode(node)
     print "\n========\n"
     node.constraints.each { |c| print c.description, "\n" } unless node.constraints.nil?
     print "\n"
     print "Incoming Constraints\n========\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n\n"
     fixConstraints(node,constraints)
     
     print "\n Node = "
     printNode(node)
     print "\n========\n"
     node.constraints.each { |c| print c.description, "\n" } unless node.constraints.nil?
     print "\n"
     print "Outgoing Constraints\n========\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n"
     
     #Test 4
     print "TEST 4\n-----------\n"
     node = Node.new(1,1,1)
     n1 = Node.new(1,1,1)
     c1 = Constraint.new('TestConstraint')
     c2 = Constraint.new("testcon2")
     constraints = []
     node.constraints = [c1]
     c1.nodes = [n1]
     n1.constraints = [c2]
     print "\nNode = "
     printNode(node)
     print "\n========\n"
     node.constraints.each { |c| print c.description, "\n" } unless node.constraints.nil?
     print "\n"
     print "Incoming Constraints\n========\n"
     constraints.each { |c| print c.description, "\n" } unless constraints.nil?
     print "\n\n"
     
     oldConstraints = Array.new(constraints)
     
     fixConstraints(node,constraints)
     
     newConstraints = constraints.select { |c| oldConstraints.include? c == false }
     
     print "\n Node = "
     printNode(node)
     print "\n========\n"
     node.constraints.each { |c| print c.description, "\n" } unless node.constraints.nil?
     print "\n"
     print "\nOutgoing Constraints\n========\n"
     constraints.each do |c| 
          print c.description, "\n" 
     end unless constraints.nil?
     print "\n"
     
     uncoveredNodes = []
     node.constraints.each { |c| c.nodes.each { |n| uncoveredNodes.push(n)}}
     
     uncoveredNodeConstraints = []
     
     print "\nUncovered Nodes and their constraints\n==========\n"
     uncoveredNodes.each do |n|
          print "\nNode = "
          printNode(n)
          print "\n========\n"
          n.constraints.each do |c| 
               print c.description, "\n"
               uncoveredNodeConstraints.push(c)
          end unless n.constraints.nil?
          print "\n"
     end
     
     print "\nUncovered Node Constraints and their Node Lists\n========\n"
     uncoveredNodeConstraints.each do |c| 
          print c.description, "\n" 
          c.nodes.each do |n|
               print " -Node: "
               printNode(n)
               print "\n---\n"
          end
     end unless uncoveredNodeConstraints.nil?
     print "\n"
end

def uncoverNodesAndConstraintsTest()
     # test 1
     
     print "\nTEST 1\n=========\n\n"
     c = Constraint.new('test')
     uncoverNodesAndConstraints(c)
     print "Nodes of c and their constraints\n----------\n"
     newConstraints = []
     c.nodes.each do |n|
          print "\nNode = "
          printNode(n)
          print "\n========\n"
          n.constraints.each do |con| 
               print con.description, "\n"
               newConstraints.push(c)
          end unless n.constraints.nil?
          print "\n"
     end unless c.nodes.nil?
     print "\n"
     
     print "Constraints found and their nodes\n-----------\n"
     newConstraints.each do |con| 
          print con.description, "\n" 
          con.nodes do |n|
               print " -Node: "
               printNode(n)
               print "\n---\n"
          end
     end unless newConstraints.nil?
     print "\n"
     
     # test 2
     
     print "\nTEST 2\n=========\n\n"
     c = Constraint.new('test')
     n = Node.new(1,1,1)
     c.nodes = [n]
     uncoverNodesAndConstraints(c)
     print "Nodes of c and their constraints\n----------\n"
     newConstraints = []
     c.nodes.each do |n|
          print "\nNode = "
          printNode(n)
          print "\n========\n"
          n.constraints.each do |con| 
               print con.description, "\n"
               newConstraints.push(c)
          end unless n.constraints.nil?
          print "\n"
     end unless c.nodes.nil?
     print "\n"
     
     print "Constraints found and their nodes\n-----------\n"
     newConstraints.each do |con| 
          print con.description, "\n" 
          con.nodes do |n|
               print " -Node: "
               printNode(n)
               print "\n---\n"
          end
     end unless newConstraints.nil?
     print "\n"
     
     # test 3
     
     print "\nTEST 3\n=========\n\n"
     c = Constraint.new('test')
     n = Node.new(1,1,1)
     c2 = Constraint.new('test2')
     c.nodes = [n]
     n.constraints = [c2]
     uncoverNodesAndConstraints(c)
     print "Nodes of c and their constraints\n----------\n"
     newConstraints = []
     c.nodes.each do |n|
          print "\nNode = "
          printNode(n)
          print "\n========\n"
          n.constraints.each do |con| 
               print con.description, "\n"
               newConstraints.push(con)
          end unless n.constraints.nil?
          print "\n"
     end unless c.nodes.nil?
     print "\n"
     
     print "Constraints found and their nodes\n-----------\n"
     newConstraints.each do |con| 
          print con.description, "\n" 
          con.nodes.each do |n|
               print " -Node: "
               printNode(n)
               print "\n---\n"
          end
     end unless newConstraints.nil?
     print "\n"
     
     # test 4
     
     print "\nTEST 4\n=========\n\n"
     c = Constraint.new('test')
     n = Node.new(1,1,1)
     n2 = Node.new(1,1,1)
     c2 = Constraint.new('test2')
     c.nodes = [n, n2]
     n.constraints = [c2]
     n2.constraints = [c2]
     uncoverNodesAndConstraints(c)
     print "Nodes of c and their constraints\n----------\n"
     newConstraints = []
     c.nodes.each do |n|
          print "\nNode = "
          printNode(n)
          print "\n========\n"
          n.constraints.each do |con| 
               print con.description, "\n"
               newConstraints.push(con)
          end unless n.constraints.nil?
          print "\n"
     end unless c.nodes.nil?
     print "\n"
     
     print "Constraints found and their nodes\n-----------\n"
     newConstraints.each do |con| 
          print con.description, "\n" 
          con.nodes.each do |n|
               print " -Node: "
               printNode(n)
               print "\n---\n"
          end
     end unless newConstraints.nil?
     print "\n"
     
     # test 5
     
     print "\nTEST 5\n=========\n\n"
     c = Constraint.new('test')
     n = Node.new(1,1,1)
     n2 = Node.new(1,1,1)
     c2 = Constraint.new('test2')
     c.nodes = [n, n2]
     n.constraints = [c2,c]
     n2.constraints = [c2,c ]
     uncoverNodesAndConstraints(c)
     print "Nodes of c and their constraints\n----------\n"
     newConstraints = []
     c.nodes.each do |n|
          print "\nNode = "
          printNode(n)
          print "\n========\n"
          n.constraints.each do |con| 
               print con.description, "\n"
               newConstraints.push(con) unless newConstraints.include?(con)
          end unless n.constraints.nil?
          print "\n"
     end unless c.nodes.nil?
     print "\n"
     
     print "Constraints found and their nodes\n-----------\n"
     newConstraints.each do |con| 
          print con.description, "\n" 
          con.nodes.each do |n|
               print " -Node: "
               printNode(n)
               print "\n---\n"
          end
     end unless newConstraints.nil?
     print "\n"
end

def fixNodeConstraintsTest()
     #Test 1
     
     print "\nTEST 1\n============\n"
     n = Node.new(1,1,1)
     constraints = []
     print "\nNode = "
     printNode(n)
     print "\n========\n"
     n.constraints.each do |con| 
          print con.description, "\n"
          constraints.push(con)
     end unless n.constraints.nil?
     print "\n"
     
     fixNodeConstraints(n)
     
     print "\nConstraints Found and their Nodes\n------------\n"
     constraints.each do |con| 
          print con.description, "\n" 
          con.nodes.each do |n|
               print " -Node: "
               printNode(n)
               print "\n---\n"
          end
     end unless constraints.nil?
     print "\n\n"
     
     #Test 2
     
     print "\nTEST 2\n============\n"
     n = Node.new(1,1,1)
     c = Constraint.new('Test')
     n.constraints = [c]
     constraints = []
     print "\nNode = "
     printNode(n)
     print "\n========\n"
     n.constraints.each do |con| 
          print con.description, "\n"
          constraints.push(con)
     end unless n.constraints.nil?
     print "\n"
     
     fixNodeConstraints(n)
     
     print "\nConstraints Found and their Nodes\n------------\n"
     constraints.each do |con| 
          print con.description, " with ", con.nodes.length, " nodes\n" 
          con.nodes.each do |n|
               print " -Node: "
               printNode(n)
               print "\n---\n"
          end
     end unless constraints.nil?
     print "\n\n"
     
     #Test 3
     
     print "\nTEST 3\n============\n"
     n = Node.new(1,1,1)
     c = Constraint.new('Test')
     c1 = Constraint.new('test1')
     n.constraints = [c, c1]
     constraints = []
     print "\nNode = "
     printNode(n)
     print "\n========\n"
     n.constraints.each do |con| 
          print con.description, "\n"
          constraints.push(con)
     end unless n.constraints.nil?
     print "\n"
     
     fixNodeConstraints(n)
     
     print "\nConstraints Found and their Nodes\n------------\n"
     constraints.each do |con| 
          print con.description, " with ", con.nodes.length, " nodes\n" 
          con.nodes.each do |n|
               print " -Node: "
               printNode(n)
               print "\n---\n"
          end
     end unless constraints.nil?
     print "\n\n"
     
     #Test 4
     
     print "\nTEST 4\n============\n"
     n = Node.new(1,1,1)
     c = Constraint.new('Test')
     c1 = Constraint.new('test1')
     c3 = Constraint.new('testultimate')
     n.constraints = [c, c1, c3]
     constraints = []
     print "\nNode = "
     printNode(n)
     print "\n========\n"
     n.constraints.each do |con| 
          print con.description, "\n"
          constraints.push(con)
     end unless n.constraints.nil?
     print "\n"
     
     fixNodeConstraints(n)
     
     print "\nConstraints Found and their Nodes\n------------\n"
     constraints.each do |con| 
          print con.description, " with ", con.nodes.length, " nodes\n" 
          con.nodes.each do |n|
               print " -Node: "
               printNode(n)
               print "\n---\n"
          end
     end unless constraints.nil?
     print "\n\n"
end

#fixNodeConstraintsTest()
#uncoverNodesAndConstraintsTest()
#fixConstraintsTest()
#backtrackTest()
#turnSolutionIntoArrayTest()
#addToStackTest()
#findNextConstraintTest()
#removeNodeTest()
#makeGroupListTest()
#assignNodesToConstraintsTest()
#getSudokuMatrixTest()
#getConstraintsTest()
#getNodesTest()
#printConstraintTest()
#printNodeTest()
#findNodesTest()
#printArrayTest()
solvePuzzleTest()
#preloadPuzzleTest()
